using System;
using System.Collections.Generic;
using System.Linq;
using Sustainalytics.ClientDW.Entities;
using Sustainalytics.DataLayer.Shared;
using MongoDB.Driver;
using Sustainalytics.Entities.ESGRatings;
using Sustainalytics.Entities;
using Sustainalytics.Utils;

namespace Sustainalytics.ESGRatings.BusinessLogic
{

    public class EsgThresholdManager<T, TU> where T : EsgThreshold<TU>, IEntity
    {
        private readonly IRepositoryCollection<T> _repositoryFocus;
        private IMongoDatabase _clientDwDatabase;

        public EsgThresholdManager(string conn)
            : this(new RepositoryCollection<T>(conn))
        {
            var clientDwConnectionString = MongoUrl.Create(conn);

            if (string.IsNullOrWhiteSpace(clientDwConnectionString.DatabaseName))
            {
                throw new ArgumentException("No database specified in the connection string!");
            }

            var clientDwClient = new MongoClient(clientDwConnectionString);
            _clientDwDatabase = clientDwClient.GetDatabase(clientDwConnectionString.DatabaseName);
        }

        public EsgThresholdManager(IRepositoryCollection<T> repository)
        {
            _repositoryFocus = repository;
        }

        public Dictionary<Guid, List<T>> GetCompanyEsgThresholds(List<Guid> companyIds = null)
        {
            List<CorporateData> corporates = null;
            Dictionary<string,IGrouping<string, T>> found = null;
            Dictionary<Guid, List<T>> dictionary = new Dictionary<Guid, List<T>>();

            ProjectionDefinition<CorporateData> projection = Builders<CorporateData>.Projection
                .Include(x => x.Id)
                .Include(x => x.PeerGroup);

            corporates = companyIds == null || (!companyIds.IsNullOrEmpty()) ?
                _clientDwDatabase.GetCollection<CorporateData>(typeof(CorporateData).Name)
                    .Find(FilterDefinition<CorporateData>.Empty)
                    .Project<CorporateData>(projection)
                    .ToList() :
                _clientDwDatabase.GetCollection<CorporateData>(typeof(CorporateData).Name)
                    .Find(Builders<CorporateData>.Filter.In(a => a.Id, companyIds))
                    .Project<CorporateData>(projection)
                    .ToList();

            found = _repositoryFocus.ReadAll().GroupBy(a => a.PeerGroup).ToDictionary(a => a.Key);
                
                foreach (CorporateData company in corporates)
                {
                    if (company.PeerGroup == null)
                        continue;

                    var list = new List<T>();
                    if (found.ContainsKey(company.PeerGroup))
                    {
                        list = found[company.PeerGroup]
                            .Select(a => a)
                            .OrderByDescending(a => a.LowerBound)
                            .ThenByDescending(a => a.UpperBound)
                            .ToList();
                    }

                    dictionary.Add(company.Id, list);
                }                

                return dictionary;
            
            
        }

        public bool SetupNewThresholds(List<T> thresholds)
        {
            var found = _repositoryFocus.ReadAll().FirstOrDefault();
            if (found != null)
            {
                BackupOldEsgThresholds();
                ClearCollection();
            }

            return _repositoryFocus.CreateBatch(thresholds);
        }

        private void BackupOldEsgThresholds()
        {
            var strCollection = string.Format("Backup{0}", typeof(T).Name);
            var collection = _clientDwDatabase.GetCollection<T>(strCollection);
            var oldEsgFoucs = _repositoryFocus.ReadAll();
            collection.InsertMany(oldEsgFoucs);
        }

        private void ClearCollection()
        {
            _repositoryFocus.DeleteAll();
        }
    }
}